import os   
import sys
import logging
import asyncore
import time
import executer.manager 
from  connecter import Connecter
from protocolhandler import ProtocolHandler
from clientconfig import ClientConfig 
from multiprocessing import Process
import protocol 
import svnclient
import psutil
import datetime
import shutil 
import stat

LOGGINGCFG = 'logging.cfg'

def SetDeleteFileWritalbe(f, p, e):
    try:
        os.chmod(p, stat.S_IWRITE)
        if os.path.isfile(p):
            os.remove(p)
        else:
            os.removedirs(p)
    except Exception:
        pass


def DeleteTaskPath(dirs):
    for v in dirs:
        try:
            if os.path.isdir(v):
                shutil.rmtree(v, False, SetDeleteFileWritalbe)
            else:
                os.remove(v)
        except Exception:
            logging.exception('delete path error')

TASK_PATH = 'taskpath'

class AutomationClient():
    last_connect_time = None
    def __init__(self):
        self.login_success = False
        self.quit = False
        self.connecter  = Connecter() 
        self.svn = svnclient.SvnClien()
        self.protocol_handler = ProtocolHandler(self.connecter)
        self.config  = ClientConfig()
        self.last_performan_time = None
        self.disk_clearup_time = 0
        self.delete_process = None
        self.Interval_diskcheck = datetime.timedelta(hours = 1)
        self.executer_manager  = executer.manager.Manager(self.config.uploadcfg,  self.protocol_handler, self.svn)
        self.protocol_handler.RegisterProtocol(protocol.s2c_config_request, self.OnConfigRequest)
        self.protocol_handler.RegisterProtocol(protocol.s2c_client_exits, self.OnQuitRequest)
        
        if not os.path.exists('log'):
            os.mkdir('log')
        if os.path.exists(LOGGINGCFG):
            logging.config.fileConfig(LOGGINGCFG)
        else:
            logging.basicConfig(filename = 'log/automationclient_%s.log' % datetime.datetime.now().strftime("%Y.%m.%d_%H_%M_%S"), 
                                format='%(asctime)s %(filename)s %(lineno)d %(levelname)s %(message)s',
                                datefmt='%Y%b%d %H:%M:%S')
        console = logging.StreamHandler(sys.stdout)
        console.setLevel(logging.DEBUG)
        console.setFormatter(logging.Formatter('%(asctime)s %(filename)s %(lineno)d %(levelname)s %(message)s'))
        logging.getLogger().addHandler(console)
        logging.getLogger().setLevel(logging.DEBUG)
    
    def Init(self):
        logging.info('automationclient init')
        
        self.last_performan_time = time.time()
        
        try:
            self.config.Load('automation.cfg')
            self.connecter.connect((self.config.ip, self.config.port))
            self.last_connect_time = time.time()
            
            if not  os.path.exists('taskpath'):
                os.mkdir('taskpath')
            
            if not  os.path.exists('task/script'):
                os.makedirs('task/script')
            
        except Exception as e:
            logging.exception(e)
            return False
        
        return True
        
    def Loop(self):
        now  = time.time()
        if not asyncore.socket_map and (now - self.last_connect_time > 20):
            self.login_success = False
            self.last_connect_time = now
            logging.info('socket reconnect to server')
            self.connecter.reset_socket()
            self.connecter.connect(((self.config.ip, self.config.port)))
        
        asyncore.loop(count = 1)
        
        self.protocol_handler.Loop()
        self.executer_manager.Loop()
        
        if now - self.last_performan_time > 10 and self.login_success:
            self.last_performan_time = now
            self.SendPreformanInfo()
            
        if now - self.disk_clearup_time > 60 * 60:
            self.disk_clearup_time = now
            self.ClearUpDisk()
                
    def ClearUpDisk(self):
        if (psutil.disk_usage("/").free /1024 /1024) > 300:
            return
        
        if self.delete_process:
            if self.delete_process.is_alive():
                return
            else:
                self.delete_process.join()
                self.delete_process = None
            
        now = time.time()
        deletedirs = []
        for v in os.listdir(TASK_PATH):
            p = os.path.join(TASK_PATH, v)
            taskid  = 0
            try:
                taskid = int(p.split('_')[-1])
            except ValueError:
                pass
            if now - os.path.getctime(p) > (60 * 60 * 12) and not self.executer_manager.HasTask(taskid):
                deletedirs.append(p)
        
        if len(deletedirs) > 0:
            logging.info('clear up disk')
            self.delete_process = Process(target = DeleteTaskPath, args = (deletedirs,))
            self.delete_process.start()
            
            
    def Uninit(self):
        self.executer_manager.StopAll()
        self.connecter.close()
        logging.info('socket close')
    
    
    def OnConfigRequest(self, request):
        self.login_success = True
        logging.info('login in server')
        self.config.SetUploadFileConfig(request.ftpip, request.ftpport, request.ftpuser, request.ftppassword)
        self.svn.SetSvnInfo(request.svnpath, request.svnuser, request.svnpassword)
        
    def SendPreformanInfo(self):
        request = protocol.C2SPreformanInfoRequest()
        request.cpu_percent = psutil.cpu_percent()
        request.mem_percent = psutil.phymem_usage().percent
        request.free_disk = psutil.disk_usage("/").free /1024 /1024
        self.protocol_handler.DoSend(request)
        
        
    def OnLoginInServer(self):
        running_tasks =  self.executer_manager.task_list.keys()
        if len(running_tasks) > 0:
            request = protocol.C2SRuningTask()
            request.tasks = running_tasks[:]
            self.protocol_handler.DoSend(request)
            
    def OnQuitRequest(self, request):
        logging.info("receive server quit request %s" % request.message)
        self.quit = True
        
        
    def IsQuit(self):
        return self.quit